<?php

/**
 * @author Thomas
 *
 */
class GpxDataParser extends AbstractDataParser implements IGpsLogDataParser {

	/**
	 *
	 */
	function __construct() {
		date_default_timezone_set('GMT');
	}

	/**
	 *(non-PHPdoc)
	 * @see IGpsLogDataParser::parse()
	 */
	public function parse($sourceFile) {

		$this->xml = simplexml_load_file($sourceFile);

		// Parsing track
		$xmlTrackPts = $this->xml->trk->trkseg->trkpt;

		$gpsTrackData = Array();

		$previousGpsPt = null;
		$speedData = Array();
		$distanceData = Array();
		$traveledDistance = 0;
		$timeElapsed = 0;

		$count = 0;

		foreach ($xmlTrackPts as $pt) {

			$time = (string) $pt->time;
			$time = new DateTime($time);
			$time->setTimezone(new DateTimeZone("Europe/paris"));
			$formatedTime = $time->format('Y-m-d\TH:i:s.u\Z');

			// Find time at point
			$microTime = doubleval(($time->getTimestamp() + $time->getOffset()) . "." . $time->format('u'));// + doubleval($microTime["fraction"]);

			// Finding current speed at point
			$currentSpeedKph = 0;
			$deltaDistance = 0;
			$deltaTime = 0;
			$accel = 0;
			// Finding speed....
			if ($previousGpsPt != null) {

				$deltaDistance = $this->giveDistanceInMeters($previousGpsPt["latitude"], $previousGpsPt["longitude"], doubleval($pt->attributes()->lat), doubleval($pt->attributes()->lon)); // meters
				$deltaTime = $microTime - $previousGpsPt["microTime"]; // seconds
				$currentSpeedKph = $deltaDistance / $deltaTime * 3.6; // 3600s * 10e-3 (m to km)

				$accel = ($currentSpeedKph - $previousGpsPt["currentSpeedKph"]) / $deltaTime;

				if (abs($accel) > 25) {
// 					$accel = 0;
					$currentSpeedKph = $this->Clamp($previousGpsPt["currentSpeedKph"], 0, $previousGpsPt["currentSpeedKph"]);
				}

				// 				$currentSpeedKph = $this->Clamp($currentSpeedKph, 0, 55);
			}

			$traveledDistance += $deltaDistance;
			$timeElapsed += $deltaTime;

			$gpsDataPt = Array("time" => $formatedTime, "microTime" => $microTime, "latitude" => doubleval($pt->attributes()->lat), "longitude" => doubleval($pt->attributes()->lon), "elevation" => doubleval($pt->ele), "deltaMeters" => $deltaDistance,
					"deltaTime" => /*(($deltaTime > 5) ? "WARN BIG DT " : "").*/$deltaTime, "timeElapsed" => $timeElapsed, "traveledDistance" => $traveledDistance, "currentSpeedKph" => /*(($currentSpeedKph > 50) ? "WARN BIG SPEED " : "").*/$currentSpeedKph, "acceleration" => $accel);

			array_push($gpsTrackData, $gpsDataPt);
			array_push($speedData, $currentSpeedKph);
			array_push($distanceData, $deltaDistance);

			// Store point to calcute speed next loop
			$previousGpsPt = $gpsDataPt;

			// Getting start date
			if ($count == 0) {
				$startTime = $formatedTime;
				$startTimeTS = $microTime;
			}

			$count++;
		}

		$basicInfos = Array("startTime" => $startTime, "startTimeTS" => $startTimeTS, "totalTime" => $timeElapsed, "totalDistance" => $traveledDistance);
		$this->data = Array("gpsDataInfos" => $basicInfos, "gpsTrackData" => $gpsTrackData);

	}

	public function giveDistanceInMeters($lat1, $lon1, $lat2, $lon2) {

		$R = 6371; // km
		$dLat = deg2rad($lat2 - $lat1);
		$dLon = deg2rad($lon2 - $lon1);
		$lat1 = deg2rad($lat1);
		$lat2 = deg2rad($lat2);
		$a = sin($dLat / 2) * sin($dLat / 2) + sin($dLon / 2) * sin($dLon / 2) * cos($lat1) * cos($lat2);
		$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
		$d = $R * $c;
		return $d * 1000; // km to meters
	}

	/* (non-PHPdoc)
	 * @see AbstractDataParser::cast()
	 */
	public function cast($class, $object) {
		// TODO: Auto-generated method stub

	}

	/**
	 *(non-PHPdoc)
	 * @see IGpsLogDataParser::getGpsData()
	 */
	public function getGpsData() {
		return $this->data;
	}

	function Clamp($int, $min, $max) {
		if (is_numeric($int) && is_numeric($min) && is_numeric($max)) {
			if ($int < $min)
				$int = $min;
			if ($int > $max)
				$int = $max;
			return $int;
		}
	}
}

?>
